import 'dart:convert';

import 'package:eplorex/im/message_cmd.dart';
import 'package:eplorex/models/message/chat_message_type.dart' as types;
import 'package:eplorex/models/message/message_content.dart';
import 'package:eplorex/pages/message/group/group_detail_page.dart';
import 'package:eplorex/pages/message/state/inherited_user.dart';
import 'package:eplorex/pages/message/wx_popup_menu_widget.dart';
import 'package:eplorex/pages/my/user_profile_page.dart';
import 'package:eplorex/providers/user_session.dart';
import 'package:eplorex/utils/im_util.dart';
import 'package:eplorex/widgets/message/unread_header.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:oktoast/oktoast.dart';
import 'package:uuid/uuid.dart';

import '../../dao/conversation_dao.dart';
import '../../im/im_sdk_client.dart';
import '../../im/message_utils.dart';
import '../../models/message/message.dart';
import '../../models/server_message.dart';
import '../../providers/local_db.dart';
import '../../providers/user_context.dart';
import 'chat/chat.dart';
import 'state/chat_theme.dart';

class ConversationDetailPage extends StatefulWidget {
  final String title;
  int convType = 0;
  final int cid;
  final int senderId;
  final int partnerId;

  ConversationDetailPage(
      @required this.title, @required this.cid, this.senderId, this.partnerId,
      {super.key, this.convType = 0});

  @override
  State<ConversationDetailPage> createState() => _ConversationDetailPageState();
}

class _ConversationDetailPageState extends State<ConversationDetailPage> {
  List<types.Message> _messages = [];
  final _user = transfer(UserContext.cxt()!);
  MessageCallBack? _messageCallBack;

  @override
  void initState() {
    super.initState();
    _loadMessages();
    _messageCallBack = (message) => _addLocalCache(message);
    IMSdkClient.registerCallback(_messageCallBack!);
  }

  @override
  void dispose() {
    super.dispose();
    IMSdkClient.unRegisterCallback(_messageCallBack!);
  }

  void _handleAttachmentPressed() {
    showModalBottomSheet<void>(
      context: context,
      builder: (BuildContext context) => SafeArea(
        child: SizedBox(
          height: 144,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              TextButton(
                onPressed: () {
                  Navigator.pop(context);
                  _handleImageSelection();
                },
                child: const Align(
                  alignment: AlignmentDirectional.centerStart,
                  child: Text('Photo'),
                ),
              ),
              TextButton(
                onPressed: () {
                  Navigator.pop(context);
                  // _handleFileSelection();
                },
                child: const Align(
                  alignment: AlignmentDirectional.centerStart,
                  child: Text('File'),
                ),
              ),
              TextButton(
                onPressed: () => Navigator.pop(context),
                child: const Align(
                  alignment: AlignmentDirectional.centerStart,
                  child: Text('Cancel'),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  // void _handleFileSelection() async {
  //   final result = await FilePicker.platform.pickFiles(
  //     type: FileType.any,
  //   );
  //
  //   if (result != null && result.files.single.path != null) {
  //     final message = types.FileMessage(
  //       author: _user,
  //       createdAt: DateTime.now().millisecondsSinceEpoch,
  //       id: const Uuid().v4(),
  //       mimeType: lookupMimeType(result.files.single.path!),
  //       name: result.files.single.name,
  //       size: result.files.single.size,
  //       uri: result.files.single.path!,
  //     );
  //
  //     _addMessage(message);
  //   }
  // }

  void _handleImageSelection() async {
    final result = await ImagePicker().pickImage(
      imageQuality: 70,
      maxWidth: 1440,
      source: ImageSource.gallery,
    );

    if (result != null) {
      final bytes = await result.readAsBytes();
      final image = await decodeImageFromList(bytes);

      final message = types.ImageMessage(
          author: _user,
          createdAt: DateTime.now().millisecondsSinceEpoch,
          height: image.height.toDouble(),
          id: const Uuid().v4(),
          name: result.name,
          size: bytes.length,
          uri: result.path,
          width: image.width.toDouble(),
          messageContent: ImageMessageContent.fromParams(
              result.name,
              image.width.toDouble(),
              image.height.toDouble(),
              bytes.length,
              result.path));

      _addCacheAndSendMessage(message);
    }
  }

  void _handleMessageTap(BuildContext _, types.Message message) async {
    print("_handleMessageTap !!!");
    // if (message is types.FileMessage) {
    //   var localPath = message.uri;
    //
    //   if (message.uri.startsWith('http')) {
    //     try {
    //       final index =
    //       _messages.indexWhere((element) => element.id == message.id);
    //       final updatedMessage =
    //       (_messages[index] as types.FileMessage).copyWith(
    //         isLoading: true,
    //       );
    //
    //       setState(() {
    //         _messages[index] = updatedMessage;
    //       });
    //
    //       final client = http.Client();
    //       final request = await client.get(Uri.parse(message.uri));
    //       final bytes = request.bodyBytes;
    //       final documentsDir = (await getApplicationDocumentsDirectory()).path;
    //       localPath = '$documentsDir/${message.name}';
    //
    //       if (!File(localPath).existsSync()) {
    //         final file = File(localPath);
    //         await file.writeAsBytes(bytes);
    //       }
    //     } finally {
    //       final index =
    //       _messages.indexWhere((element) => element.id == message.id);
    //       final updatedMessage =
    //       (_messages[index] as types.FileMessage).copyWith(
    //         isLoading: null,
    //       );
    //
    //       setState(() {
    //         _messages[index] = updatedMessage;
    //       });
    //     }
    //   }
    //
    //   await OpenFilex.open(localPath);
    // }
  }

  void _handlePreviewDataFetched(
    types.TextMessage message,
    types.PreviewData previewData,
  ) {
    final index = _messages.indexWhere((element) => element.id == message.id);
    final updatedMessage = (_messages[index] as types.TextMessage).copyWith(
      previewData: previewData,
    );

    setState(() {
      _messages[index] = updatedMessage;
    });
  }

  void _handleSendPressed(types.PartialText message) {
    final textMessage = types.TextMessage(
        author: _user,
        createdAt: DateTime.now().millisecondsSinceEpoch,
        id: const Uuid().v4(),
        text: message.text,
        messageContent: TextMessageContent.fromParams(message.text));

    _addCacheAndSendMessage(textMessage);
  }

  Future<List<types.Message>> _loadMessages() async {
    // 已经本地有cache 了，不要再从server load 了.
    if(_messages!=null && _messages.length!=0){
      return _messages;
    }
    List<Map<String, dynamic>> cachedMsg =
        await DatabaseHelper.instance.queryMessagesInConv(widget.senderId,widget.partnerId);
    final cachedTmpMsg = cachedMsg
        .map((e) => types.Message.fromJson(jsonDecode(e['content'])))
        .toList();
    List<ServerMessage> serverMsg =
        await ConversationDao.queryConvMessage(widget.cid);

    final serverTmpMsg =
        await Future.wait(List.generate(serverMsg.length, (i) async {
      ServerMessage msg = serverMsg[i];
      var msgContent = jsonDecode(msg.messageContent ?? "");
      var sender = await UserSession.instance.getUser(msg.senderId!);
      int idx= cachedTmpMsg.indexWhere((element) => element.id == msg.uuid);
      if(idx!=-1){
        cachedTmpMsg.removeAt(idx);
      }
      if (sender != null) {
        return types.Message.fromJson({
          'author': sender?.toJson(),
          'id': msg.messageId.toString(),
          'createdAt': msg.createTime,
          'status': Status.values[msg.status?.toInt() ?? 0].name,
          'updatedAt': msg.updateTime,
          'messageContent': msgContent,
          'type': MessageType.values[msg.messageType?.toInt() ?? 0].name,
          ...msgContent
        });
      }
    }));

    final finalMessage = MesssageUtil.mergeMessage(cachedTmpMsg, serverTmpMsg);
    finalMessage.sort((o1, o2) => o2!.createdAt! - o1.createdAt!);
    return finalMessage;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title!),
        actions: [
          IconButton(
              onPressed: () {
                Navigator.of(context).push(MaterialPageRoute(builder: (_) {
                  return widget.convType == 0
                      ? UserProfilePage(userId: widget.partnerId)
                      : GroupDetailPage(groupId: widget.partnerId);
                }));
              },
              icon: const Icon(Icons.more_horiz))
        ],
      ),
      body: FutureBuilder(
        builder: (BuildContext context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Container(
              child: CircularProgressIndicator(),
            );
          } else if (snapshot.hasError) {
            return Container(
              child: Text("错误"),
            );
          }

          _messages = snapshot?.data ?? [];
          return Chat(
            messages: _messages,
            onAttachmentPressed: _handleAttachmentPressed,
            onMessageTap: _handleMessageTap,
            onPreviewDataFetched: _handlePreviewDataFetched,
            onSendPressed: _handleSendPressed,
            // onBackgroundTap: _handleBackgroundTap,
            showUserAvatars: true,
            showUserNames: true,
            user: _user,
            onMessageLongPress: _onMsgLongPressed,
            theme: const DefaultChatTheme(
              bubbleMargin: EdgeInsets.all(8),
              seenIcon: Text(
                'read',
                style: TextStyle(
                  fontSize: 10.0,
                ),
              ),
            ),
            scrollToUnreadOptions: ScrollToUnreadOptions(),
          );
        },
        future: _loadMessages(),
      ),
    );
  }

  void _onMsgLongPressed(BuildContext context, types.Message msg) {
    final user = InheritedUser.of(context).user;
    final currentUserIsAuthor = user.uid == msg.author.uid;
    bool isCanRecall = true;
    var actions = ['转发', '删除'];
    var menuWidth = 180.0;
    var menuHeight = 50.0;
    var pageMaxChildCount = 5;
    if (isCanRecall && currentUserIsAuthor) {
      actions.add('撤回');
      menuWidth = 200.0;
    }
    if (msg.type == types.MessageType.text) {
      actions.add('复制');
    }
    Navigator.push(
            context,
            PopupMenuRoute(context, actions, pageMaxChildCount, Colors.black54,
                menuWidth, menuHeight, null, null))
        .then((selected) {
      if (selected != null) {
        switch (actions[selected]) {
          case '复制':
            showToast('复制成功');
            Clipboard.setData(
                ClipboardData(text: (msg as types.TextMessage).text));
            break;
          case '转发':
            _selectMemberPage(msg);
            break;
          case '删除':
            _deleteMsg(msg);
            break;
          case '撤回':
            _recallMsg(msg);
            break;
        }
      }
    });
  }

  void _addLocalCache(types.Message message,{int? cid}){
    DatabaseHelper.instance.insertMessage({
      'cid':cid,
      'msgId': message.id,
      "createdAt": DateTime.now().millisecondsSinceEpoch,
      "senderId": widget.senderId,
      "receiverId": widget.partnerId,
      "status": message.status ?? Status.sending.name,
      "content": jsonEncode(message),
      "type": message.type.name
    });
    setState(() {
      _messages.insert(0, message);
    });
  }

  void _addCacheAndSendMessage(types.Message message,{int? cid}) {
    _addLocalCache(message,cid: cid);
    IMSdkClient.sendMessage(
        uuid: message.id,
        widget.senderId.toString(),
        widget.partnerId.toString(),
        widget.convType,
        widget.cid,
        MessageCmd.sendMsg.index, {
      'messageType': message.type.name,
      'messageContent': message.messageContent,
    });
  }

  _deleteMsg(types.Message msg) {
    DatabaseHelper.instance.deleteMessage(msg.id);
    final index = _messages.indexWhere((element) => element.id == msg.id);
    if (index >= 0) {
      setState(() {
        _messages.removeAt(index);
      });
    }
    IMSdkClient.sendMessage(
        widget.senderId.toString(),
        widget.partnerId.toString(),
        widget.convType,
        widget.cid,
        MessageCmd.deleteMsg.index,
        {'msgId': msg.id});
  }

  _recallMsg(types.Message msg) {
    final index = _messages.indexWhere((element) => element.id == msg.id);
    setState(() {
      _messages.removeAt(index);
    });
    IMSdkClient.sendMessage(
        widget.senderId.toString(),
        widget.partnerId.toString(),
        widget.convType,
        widget.cid,
        MessageCmd.recallMsg.index,
        {'msgId': msg.id});
  }

  _selectMemberPage(types.Message msg) {}
}
